package com.wzdigit.wms.wms.service.basic;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.wzdigit.framework.Shift;
import com.wzdigit.mes.basic.api.BasicVendorApi;
import com.wzdigit.mes.basic.dto.VendorDTO;
import com.wzdigit.mes.prp.api.WorkFactoryApi;
import com.wzdigit.wms.basic.client.Pager;
import com.wzdigit.wms.basic.client.PagerInfo;
import com.wzdigit.wms.basic.client.request.basic.*;
import com.wzdigit.wms.basic.client.response.Result;
import com.wzdigit.wms.basic.client.response.basic.*;
import com.wzdigit.wms.basic.domain.basic.Warehouse;
import com.wzdigit.wms.basic.domain.basic.WorkDivision;
import com.wzdigit.wms.basic.domain.basic.WorkDivisionDtl;
import com.wzdigit.wms.basic.domain.basic.Zone;
import com.wzdigit.wms.basic.enums.BaseIsEnabledEnum;
import com.wzdigit.wms.basic.enums.workdivision.WorkDivisionTypeEnum;
import com.wzdigit.wms.basic.mapper.core.basic.WarehouseMapper;
import com.wzdigit.wms.basic.mapper.core.basic.WorkDivisionDtlMapper;
import com.wzdigit.wms.basic.mapper.core.basic.WorkDivisionMapper;
import com.wzdigit.wms.basic.mapper.core.basic.ZoneMapper;
import com.wzdigit.wms.common.utils.HttpExcel;
import com.wzdigit.wms.basic.util.HttpSessionUtil;
import com.wzdigit.wms.basic.util.StringUtils;
import com.wzdigit.wms.common.utils.ValidatorUtil;
import com.wzdigit.wms.common.entity.StatusCode;
import net.dreamlu.mica.core.utils.BeanUtil;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.rowset.serial.SerialException;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.*;

/**
 * 工作分工
 * @author yangdongjie
 * @DivisionOfLaborService.java
 * @2021年3月11日下午1:57:22
 */
@Service
public class WorkDivisionService {
	
	@Autowired
	private ZoneMapper zoneMapper;
	
	@Autowired
	private WarehouseMapper warehouseMapper;
	
	@Autowired
	private WorkDivisionMapper workDivisionMapper;
	
	@Autowired
	private WorkDivisionDtlMapper workDivisionDtlMapper;
	
	@Reference(version = "${dubbo.consumers.basic.vendor.api:1.0.0}", check = false, timeout = 300000)
	private BasicVendorApi basicVendorApi;
	
	@Reference(version = "${dubbo.consumers.prp.work.factory.api:1.0.0}", check = false, timeout = 300000)
	private WorkFactoryApi workFactoryApi;
	
	/**
	 * 创建工作分工
	 * @param dto
	 * @param servletRequest
	 * @return
	 */
	@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public <T> Result<T> createWorkDivision(CreateWorkDivisionRequest dto,
    		HttpServletRequest servletRequest) {
    	String loginName = HttpSessionUtil.getLoginName(servletRequest);
    	WorkDivision workDivision = new WorkDivision();
    	BeanUtil.copyNonNull(dto, workDivision);
    	workDivision.setCreateUser(loginName);
    	workDivision.setCreateTime(new Date());
    	workDivisionMapper.insert(workDivision);
    	return new Result<>();
	}
	
	/**
	 * 修改工作分工
	 * @param dto
	 * @param servletRequest
	 * @return
	 */
	@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public <T> Result<T> updateWorkDivision(UpdateWorkDivisionRequest dto,
    		HttpServletRequest servletRequest) {
    	String loginName = HttpSessionUtil.getLoginName(servletRequest);
    	WorkDivision workDivision = new WorkDivision();
    	BeanUtil.copy(dto, workDivision);
    	workDivision.setModifyUser(loginName);
    	workDivision.setModifyTime(new Date());
    	workDivisionMapper.updateById(workDivision);
    	return new Result<>();
	}
	
	/**
	 * 启用/禁用 工作分工
	 * @param dto
	 * @param servletRequest
	 * @return
	 */
	@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public <T> Result<T> updateWorkDivisionIsEnabled(UpdateWorkDivisionIsEnabledRequest dto,
    		HttpServletRequest servletRequest) {
    	String loginName = HttpSessionUtil.getLoginName(servletRequest);
    	
    	WorkDivision workDivision = new WorkDivision();
    	workDivision.setWorkDivisionId(dto.getWorkDivisionId());
    	workDivision.setIsEnabled(dto.getIsEnabled());
    	workDivision.setModifyUser(loginName);
    	workDivision.setModifyTime(new Date());
    	workDivisionMapper.updateById(workDivision);
    	return new Result<>();
	}
	
	/**
	 * 查询工作分工
	 * @param workDivisionCode
	 * @param workDivisionType
	 * @param pager
	 * @return
	 */
	public <T> PagerInfo<List<WorkDivisionResponse>> searchWorkDivision(
			String workDivisionCode, Integer workDivisionType, 
			Integer isEnabled, String filter, Pager<T> pager) {
    	Page<T> page = PageHelper.offsetPage(pager.getSkipCount(), pager.getMaxResultCount());
    	PagerInfo<List<WorkDivisionResponse>> pagerInfo = new PagerInfo<>();
    	pagerInfo.setItems(workDivisionMapper.selectAll(workDivisionCode, 
    			workDivisionType, isEnabled, filter));
        pagerInfo.setTotalCount(page.getTotal());
		return pagerInfo;
    }
	
	/**
	 * 创建工作分工明细
	 * @param dto
	 * @param servletRequest
	 * @return
	 * @throws SQLException 
	 * @throws SerialException 
	 */
	@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public <T> Result<T> createWorkDivisionDtl(CreateWorkDivisionDtlRequest dto,
    		HttpServletRequest servletRequest) throws SerialException, SQLException {
		WorkDivisionDtl workDivisionDtl = new WorkDivisionDtl();
		BeanUtil.copyNonNull(dto, workDivisionDtl);
		int size = workDivisionDtlMapper.selectCountByAll(workDivisionDtl);
		if(size > 0) {
			Shift.fatal(StatusCode.DTL_DATA_EXIST);
		}
		
		String loginName = HttpSessionUtil.getLoginName(servletRequest);
		Date date = new Date();
		workDivisionDtl.setCreateUser(loginName);
		workDivisionDtl.setCreateTime(date);
		workDivisionDtlMapper.insert(workDivisionDtl);
    	return new Result<>();
	}
	
	/**
	 * 修改工作分工明细
	 * @param dto
	 * @param servletRequest
	 * @return
	 */
	@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public <T> Result<T> updateWorkDivisionDtl(UpdateWorkDivisionDtlRequest dto,
    		HttpServletRequest servletRequest) {
		WorkDivisionDtl workDivisionDtl = new WorkDivisionDtl();
		BeanUtil.copy(dto, workDivisionDtl);
		
		workDivisionDtl.setWorkDivisionDtlId(null);
		int sizeNoDtlId = workDivisionDtlMapper.selectCountByAll(workDivisionDtl);
		
		workDivisionDtl.setWorkDivisionDtlId(dto.getWorkDivisionDtlId());
		if(sizeNoDtlId > 0) {
			int sizeHaveDtlId = workDivisionDtlMapper.selectCountByAll(workDivisionDtl);
			if(sizeHaveDtlId == 0 || (sizeHaveDtlId == 1 && sizeNoDtlId > 1)){
				Shift.fatal(StatusCode.DTL_DATA_EXIST);
			}
		} 
		
		String loginName = HttpSessionUtil.getLoginName(servletRequest);
		Date date = new Date();
		workDivisionDtl.setModifyUser(loginName);
		workDivisionDtl.setModifyTime(date);
		workDivisionDtlMapper.updateById(workDivisionDtl);
    	return new Result<>();
	}
	
	/**
	 * 删除工作分工明细
	 * @param workDivisionDtlIds
	 * @param servletRequest
	 * @return
	 */
	@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public <T> Result<T> deleteWorkDivisionDtl(Integer workDivisionDtlId,
    		HttpServletRequest servletRequest) {
		workDivisionDtlMapper.deleteById(workDivisionDtlId);
		return new Result<>();
	}
	
	/**
	 * 查询工作分工明细
	 * @param workDivisionId
	 * @param pager
	 * @return
	 */
	public <T> PagerInfo<List<WorkDivisionDtlResponse>> searchWorkDivisionDtl(
			Integer workDivisionId, Pager<T> pager) {
		Page<T> page = PageHelper.offsetPage(pager.getSkipCount(), pager.getMaxResultCount());
    	PagerInfo<List<WorkDivisionDtlResponse>> pagerInfo = new PagerInfo<>();
    	pagerInfo.setItems(workDivisionDtlMapper.selectAll(workDivisionId));
        pagerInfo.setTotalCount(page.getTotal());
		return pagerInfo;
    }
	
	@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public ImportWorkDivisionResponse importWorkDivision(
			MultipartFile file, 
			HttpServletRequest servletRequest, 
			HttpServletResponse servletResponse) throws Exception {
    	String loginName = HttpSessionUtil.getLoginName(servletRequest);
    	Date date = new Date();
    	
    	List<ImportWorkDivisionRequest> excel = null;
		try {
			InputStream inputStream = file.getInputStream();
			String[] properties = { "workDivisionCode", "workDivisionType", "isEnabled", "desc", "remark" };
			excel = HttpExcel.importExcel(inputStream, ImportWorkDivisionRequest.class, properties);
		} catch (Exception e) {
			// 模板错误，请确认
			e.printStackTrace();
			Shift.fatal(StatusCode.IMPORT_DATA_ERROR);
		}
		
		if (excel == null || excel.size() == 0) {
			// 该模板数据为空
			Shift.fatal(StatusCode.IMPORT_DATA_NULL);
		}

		// 失败、成功条数
		int fail = excel.size(), sucess = 0;
		// 失败记录集合
		List<ImportWorkDivisionErrorResponse> errors = new ArrayList<>();

		for (ImportWorkDivisionRequest dto : excel) {
			boolean flag = true;

			// 1：检验参数
			for (String message : ValidatorUtil.validatorMessages(dto)) {
				ImportWorkDivisionErrorResponse error = new ImportWorkDivisionErrorResponse();
				BeanUtil.copyNonNull(dto, error);

				StringBuilder errorDec = new StringBuilder("【第");
				errorDec.append(dto.getRow()).append("行】").append(message);
				error.setRowMessage(errorDec.toString());

				errors.add(error);
				flag = false;
			}

			if (flag) {
				QueryWrapper<WorkDivision> workDivisionQueryWrapper = new QueryWrapper<>();
				workDivisionQueryWrapper.eq("WORK_DIVISION_CODE", dto.getWorkDivisionCode());
				// 编码已存在
				if (workDivisionMapper.selectCount(workDivisionQueryWrapper) > 0) {
					ImportWorkDivisionErrorResponse error = new ImportWorkDivisionErrorResponse();
					BeanUtil.copyNonNull(dto, error);

					StringBuilder errorDec = new StringBuilder("【第");
					errorDec.append(dto.getRow()).append("行】").append(StatusCode.CODE_DATA_EXIST.message());
					error.setRowMessage(errorDec.toString());

					errors.add(error);
					flag = false;
				}
				
				// 检验是否启用
				if(!BaseIsEnabledEnum.existByEnumName(dto.getIsEnabled())) {
					ImportWorkDivisionErrorResponse error = new ImportWorkDivisionErrorResponse();
					BeanUtil.copyNonNull(dto, error);

					StringBuilder errorDec = new StringBuilder("【第");
					errorDec.append(dto.getRow()).append("行】").append("是否启用错误");
					error.setRowMessage(errorDec.toString());

					errors.add(error);
					flag = false;
				}
				
				// 检验分工类别
				if(!WorkDivisionTypeEnum.existByEnumName(dto.getWorkDivisionType())) {
					ImportWorkDivisionErrorResponse error = new ImportWorkDivisionErrorResponse();
					BeanUtil.copyNonNull(dto, error);

					StringBuilder errorDec = new StringBuilder("【第");
					errorDec.append(dto.getRow()).append("行】").append("分工类别错误");
					error.setRowMessage(errorDec.toString());

					errors.add(error);
					flag = false;
				}
			}

			if (flag) {
				int isEnabled = BaseIsEnabledEnum.getEnumByName(dto.getIsEnabled()).code;
				int workDivisionType = WorkDivisionTypeEnum.getEnumByName(dto.getWorkDivisionType()).code;
				WorkDivision workDivision = new WorkDivision();
				BeanUtil.copyNonNull(dto, workDivision);
				workDivision.setCreateTime(date);
				workDivision.setCreateUser(loginName);
				workDivision.setIsEnabled(isEnabled);
				workDivision.setWorkDivisionType(workDivisionType);
				workDivisionMapper.insert(workDivision);
				--fail;
				++sucess;
			}
		}
		ImportWorkDivisionResponse response = new ImportWorkDivisionResponse();
		response.setFailureCount(fail);
		response.setSucceessCount(sucess);
		response.setItems(errors);
		return response;
	}
	
	@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public ImportWorkDivisionDtlResponse importWorkDivisionDtl(
			MultipartFile file, 
			HttpServletRequest servletRequest, 
			HttpServletResponse servletResponse) throws Exception {
    	String loginName = HttpSessionUtil.getLoginName(servletRequest);
    	Date date = new Date();
    	
    	List<ImportWorkDivisionDtlRequest> excel = null;
		try {
			InputStream inputStream = file.getInputStream();
			String[] properties = { "workDivisionCode", "factory", "vendor", "whs", "zone", "skuScop", "remark" };
			excel = HttpExcel.importExcel(inputStream, ImportWorkDivisionDtlRequest.class, properties);
		} catch (Exception e) {
			// 模板错误，请确认
			e.printStackTrace();
			Shift.fatal(StatusCode.IMPORT_DATA_ERROR);
		}
		
		if (excel == null || excel.size() == 0) {
			// 该模板数据为空
			Shift.fatal(StatusCode.IMPORT_DATA_NULL);
		}

		// 失败、成功条数
		int fail = excel.size(), sucess = 0;
		// 失败记录集合
		List<ImportWorkDivisionDtlErrorResponse> errors = new ArrayList<>();
		
		// 库区跟仓库关系<库区id，仓库id>
		Map<String, String> zoneWhsMap = new HashMap<>();
				
		// 已存在的编码<code，id>
		Map<String, Integer> isWorkDivisionIdMap = new HashMap<>();
		Map<String, String> isVendorIdMap = new HashMap<>();
		Map<String, String> isZoneIdMap = new HashMap<>();
		Map<String, String> isWhsIdMap = new HashMap<>();
		
		// 不存在的编码<code>
		Set<String> noWorkDivisionCodeSet = new HashSet<>();
		Set<String> noVendorCodeSet = new HashSet<>();
		Set<String> noZoneCodeSet = new HashSet<>();
		Set<String> noWhsCodeSet = new HashSet<>();
		
		QueryWrapper<WorkDivision> workDivisionQueryWrapper = new QueryWrapper<>();
		QueryWrapper<Warehouse> whsQueryWrapper = new QueryWrapper<>();
		QueryWrapper<Zone> zoneQueryWrapper = new QueryWrapper<>();
		for (ImportWorkDivisionDtlRequest dto : excel) {
			boolean flag = true;

			// 1：检验参数
			for (String message : ValidatorUtil.validatorMessages(dto)) {
				ImportWorkDivisionDtlErrorResponse error = new ImportWorkDivisionDtlErrorResponse();
				BeanUtil.copyNonNull(dto, error);

				StringBuilder errorDec = new StringBuilder("【第");
				errorDec.append(dto.getRow()).append("行】").append(message);
				error.setRowMessage(errorDec.toString());

				errors.add(error);
				flag = false;
			}

			Integer workDivisionId = null;
			String vendorId = null;
			String zoneId = null;
			String whsId = null;
			if (flag) {
				// 检验编码不存在
				boolean workDivisionFlag = !noWorkDivisionCodeSet.contains(dto.getWorkDivisionCode());
				if (workDivisionFlag) {
					workDivisionId = isWorkDivisionIdMap.get(dto.getWorkDivisionCode());
					if (workDivisionId == null) {
						workDivisionQueryWrapper.clear();
						workDivisionQueryWrapper.eq("WORK_DIVISION_CODE", dto.getWorkDivisionCode());
						WorkDivision workDivision = workDivisionMapper.selectOne(workDivisionQueryWrapper);
						if (workDivision == null) {
							workDivisionFlag = false;
							noWorkDivisionCodeSet.add(dto.getWorkDivisionCode());
						} else {
							workDivisionId = workDivision.getWorkDivisionId();
							isWorkDivisionIdMap.put(dto.getWorkDivisionCode(), workDivisionId);
						}
					}
				}

				if (!workDivisionFlag) {
					ImportWorkDivisionDtlErrorResponse error = new ImportWorkDivisionDtlErrorResponse();
					BeanUtil.copyNonNull(dto, error);

					StringBuilder errorDec = new StringBuilder("【第");
					errorDec.append(dto.getRow()).append("行】").append("分工编码不存在");
					error.setRowMessage(errorDec.toString());

					errors.add(error);
					flag = false;
				}
				
				// 检验供应商不存在
				if (StringUtils.isNotNull(dto.getVendor())) {
					boolean vendorFlag = !noVendorCodeSet.contains(dto.getVendor());
					if (vendorFlag) {
						vendorId = isVendorIdMap.get(dto.getVendor());
						if (vendorId == null) {
							VendorDTO vendor = basicVendorApi.getVendorByCode(dto.getVendor());
							if (vendor == null || vendor.getVendorId() == null) {
								vendorFlag = false;
								noVendorCodeSet.add(dto.getVendor());
							} else {
								vendorId = vendor.getVendorId().toString();
								isVendorIdMap.put(dto.getVendor(), vendorId);
							}
						}
					}
					
					if (!vendorFlag) {
						ImportWorkDivisionDtlErrorResponse error = new ImportWorkDivisionDtlErrorResponse();
						BeanUtil.copyNonNull(dto, error);
						
						StringBuilder errorDec = new StringBuilder("【第");
						errorDec.append(dto.getRow()).append("行】").append("供应商编码不存在");
						error.setRowMessage(errorDec.toString());
						
						errors.add(error);
						flag = false;
					}
				}
				
				// 检验仓库不存在
				if (StringUtils.isNotNull(dto.getWhs())) {
					boolean whsFlag = !noWhsCodeSet.contains(dto.getWhs());
					if (whsFlag) {
						whsId = isWhsIdMap.get(dto.getWhs());
						if (whsId == null) {
							whsQueryWrapper.clear();
							whsQueryWrapper.eq("WHS_CODE", dto.getWhs());
							Warehouse whs = warehouseMapper.selectOne(whsQueryWrapper);
							if (whs == null) {
								whsFlag = false;
								noWhsCodeSet.add(dto.getWhs());
							} else {
								whsId = whs.getWhsId().toString();
								isWhsIdMap.put(dto.getWhs(), whsId);
							}
						}
					}
					
					if (!whsFlag) {
						ImportWorkDivisionDtlErrorResponse error = new ImportWorkDivisionDtlErrorResponse();
						BeanUtil.copyNonNull(dto, error);

						StringBuilder errorDec = new StringBuilder("【第");
						errorDec.append(dto.getRow()).append("行】").append("仓库编码不存在");
						error.setRowMessage(errorDec.toString());

						errors.add(error);
						flag = false;
					}
				}
				
				// 检验库区不存在 或者 检验库区跟仓库不关联
				if (StringUtils.isNotNull(dto.getZone())) {
					boolean zoneFlag = !noZoneCodeSet.contains(dto.getZone());
					if (zoneFlag) {
						zoneId = isZoneIdMap.get(dto.getZone());
						if(zoneId == null) {
							zoneQueryWrapper.clear();
							zoneQueryWrapper.eq("ZONE_CODE", dto.getZone());
							Zone zone = zoneMapper.selectOne(zoneQueryWrapper);
							if (zone == null) {
								zoneFlag = false;
								noZoneCodeSet.add(dto.getWhs());
							} else {
								zoneId = zone.getZoneId().toString();
								isZoneIdMap.put(dto.getZone(), zoneId);
							}
						}
						
					}
					
					if(!zoneFlag) {
						ImportWorkDivisionDtlErrorResponse error = new ImportWorkDivisionDtlErrorResponse();
						BeanUtil.copyNonNull(dto, error);
						
						StringBuilder errorDec = new StringBuilder("【第");
						errorDec.append(dto.getRow()).append("行】").append("库区编码不存在");
						error.setRowMessage(errorDec.toString());
						
						errors.add(error);
						flag = false;
					}
					
					// 检验库区跟仓库不关联
					if (zoneFlag && whsId != null) {
						String whsIdStr = zoneWhsMap.get(zoneId);
						if (whsIdStr == null) {
							Warehouse whs = warehouseMapper.selectOneByZoneId(Integer.parseInt(zoneId));
							if (whs != null) {
								whsIdStr = whs.getWhsId().toString();
								zoneWhsMap.put(zoneId, whsIdStr);
							}
						}
						if (whsIdStr == null || !whsId.equals(whsIdStr)) {
							ImportWorkDivisionDtlErrorResponse error = new ImportWorkDivisionDtlErrorResponse();
							BeanUtil.copyNonNull(dto, error);

							StringBuilder errorDec = new StringBuilder("【第");
							errorDec.append(dto.getRow()).append("行】").append("库区与仓库不关联");
							error.setRowMessage(errorDec.toString());

							errors.add(error);
							zoneFlag = flag = false;
						}
					}
				}
			}

			if (flag) {
				WorkDivisionDtl workDivisionDtl = new WorkDivisionDtl();
				workDivisionDtl.setCreateTime(date);
				workDivisionDtl.setCreateUser(loginName);
				workDivisionDtl.setWorkDivisionId(workDivisionId);
				workDivisionDtl.setFactory(dto.getFactory());
				workDivisionDtl.setSkuScop(dto.getSkuScop());
				workDivisionDtl.setRemark(dto.getRemark());
				workDivisionDtl.setVendor(vendorId);
				workDivisionDtl.setZone(zoneId);
				workDivisionDtl.setWhs(whsId);
				
				int size = workDivisionDtlMapper.selectCountByAll(workDivisionDtl);
				if(size > 0) {
					ImportWorkDivisionDtlErrorResponse error = new ImportWorkDivisionDtlErrorResponse();
					BeanUtil.copyNonNull(dto, error);

					StringBuilder errorDec = new StringBuilder("【第");
					errorDec.append(dto.getRow()).append("行】").append(StatusCode.DTL_DATA_EXIST.message());
					error.setRowMessage(errorDec.toString());

					errors.add(error);
					flag = false;
				} else {
					workDivisionDtlMapper.insert(workDivisionDtl);
					--fail;
					++sucess;
				}
			}
		}
		ImportWorkDivisionDtlResponse response = new ImportWorkDivisionDtlResponse();
		response.setFailureCount(fail);
		response.setSucceessCount(sucess);
		response.setItems(errors);
		return response;
	}
}